package com.sikaryofficial.qrcode.manager;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.redis.service.RedisService;
import com.sikaryofficial.qrcode.config.ProductConfig;
import com.sikaryofficial.qrcode.constant.DownloadTaskStatusEnum;
import com.sikaryofficial.qrcode.constant.DownloadTaskTypeEnum;
import com.sikaryofficial.qrcode.domain.entity.BrandTaste;
import com.sikaryofficial.qrcode.domain.entity.DownloadTask;
import com.sikaryofficial.qrcode.domain.mapping.DownloadTaskMapping;
import com.sikaryofficial.qrcode.service.IBrandTasteService;
import com.sikaryofficial.qrcode.service.IDownloadService;
import com.sikaryofficial.qrcode.service.IDownloadTaskService;
import com.sikaryofficial.system.api.model.download.DownloadListPageReq;
import com.sikaryofficial.system.api.model.download.DownloadTaskDTO;
import com.sikaryofficial.system.api.model.download.StatusDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static com.sikaryofficial.common.core.constant.CacheBusinessConstants.PRODUCT_QRCODE_STATUS_CACHE;

/**
 * @author : qinjinyuan
 * @desc : 活动管理服务
 * @date : 2023/10/30 15:39
 */
@Service
@Slf4j
@SuppressWarnings(value = "unchecked")
public class DownloadManager {
    @Autowired
    private IDownloadTaskService downloadTaskService;
    @Autowired
    private IDownloadService remoteFileService;
    @Autowired
    private IBrandTasteService brandTasteService;
    @Autowired
    private RedisService redisService;
    @Resource
    private ProductConfig productConfig;

    public void downloadById(HttpServletResponse response, Long taskId) throws Exception {
        // 根据主键查询数据
        DownloadTask downloadTask = downloadTaskService.getOne(new LambdaQueryWrapper<DownloadTask>()
                .eq(DownloadTask::getTaskId, taskId)
                .eq(DownloadTask::getTaskStatus, DownloadTaskStatusEnum.DOWNLOADABLE.getCode())
                .eq(DownloadTask::getDeletedVersion, 0L)
        );
        if (Objects.isNull(downloadTask) || CharSequenceUtil.isBlank(downloadTask.getOfflineUrl())) {
            throw new ServiceException("the downloadTask is empty | download file is empty");
        }
        // 把下载文件资源，输出到 response 中
        File result = remoteFileService.downloadFile(downloadTask.getOfflineUrl());
        if (Objects.isNull(result)) {
            throw new ServiceException("the downloadTask is empty | download file is empty");
        }
        // 设置下载文件的响应头
        response.reset();
        response.setHeader("Content-Disposition", "attachment; filename=" + taskId.toString() + ".zip");
        response.setContentType("application/zip");
        try (InputStream inputStream = Files.newInputStream(result.toPath())) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) > 0) {
                response.getOutputStream().write(buffer, 0, length);
            }
            log.info("download success");
        } catch (Exception e) {
            log.error("download:{}", e);
            throw new ServiceException("download error.");
        }
    }

    public IPage<DownloadTaskDTO> listByObjectId(DownloadListPageReq req) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startOfDay = LocalDateTimeUtil.beginOfDay(now);
        LocalDateTime threeDaysAgo = startOfDay.minus(productConfig.getAmountToSubtract(), ChronoUnit.DAYS);
        Date startDate = Date.from(threeDaysAgo.atZone(ZoneId.systemDefault()).toInstant());

        Date endDate = Date.from(LocalDateTimeUtil.endOfDay(LocalDateTime.now()).atZone(ZoneId.systemDefault()).toInstant());

        Page<DownloadTask> customerPage = new Page<>(req.getPageNum(), req.getPageSize());
        LambdaQueryWrapper<DownloadTask> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DownloadTask::getObjectId, req.getObjectId());
        queryWrapper.eq(DownloadTask::getDeletedVersion, 0L);
        queryWrapper.eq(DownloadTask::getTaskType, DownloadTaskTypeEnum.PRODUCT_QRCODE.getCode());
        queryWrapper.eq(DownloadTask::getTaskStatus, DownloadTaskStatusEnum.DOWNLOADABLE.getCode());
        queryWrapper.between(DownloadTask::getUpdatedTime, startDate, endDate);
        queryWrapper.orderByDesc(DownloadTask::getUpdatedTime, DownloadTask::getTaskId);
        IPage<DownloadTask> downloadTaskPage = downloadTaskService.page(customerPage, queryWrapper);
        IPage<DownloadTaskDTO> taskDTOIPage = downloadTaskPage.convert(DownloadTaskMapping.INSTANCE::coverToDTO);
        if (CollUtil.isEmpty(taskDTOIPage.getRecords())) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        return taskDTOIPage;
    }

    /**
     * 获取最新任务状态
     *
     * @param objectId 业务对象ID
     * @return
     */
    public StatusDTO latestTaskStatus(Long objectId) {
        // 将 LocalDateTime 转换为 Date
        log.info("latestTaskStatus systemDefault:{}", ZoneId.systemDefault());
        // 优先判定当前是否点击了生成操作
        BrandTaste brandTaste = brandTasteService.getById(objectId);
        if (Objects.isNull(brandTaste)) {
            throw new ServiceException("the product is not exist");
        }
        String qrcodeStatusKey = MessageFormat.format(PRODUCT_QRCODE_STATUS_CACHE, brandTaste.getMd5());
        Integer status = redisService.getCacheObject(qrcodeStatusKey);
        if (Objects.nonNull(status)) {
            return StatusDTO.builder()
                    .statusDesc(DownloadTaskStatusEnum.GENERATING.getDesc())
                    .statusValue(DownloadTaskStatusEnum.GENERATING.getCode())
                    .build();
        }

        Date startDate = Date.from(LocalDateTimeUtil.beginOfDay(LocalDateTime.now()).atZone(ZoneId.systemDefault()).toInstant());
        Date endDate = Date.from(LocalDateTimeUtil.endOfDay(LocalDateTime.now()).atZone(ZoneId.systemDefault()).toInstant());
        List<Long> objectIds = Lists.newArrayList();
        objectIds.add(objectId);
        List<DownloadTask> downloadTasks = downloadTaskService.getLatestTaskStatus(objectIds, startDate, endDate);
        if (CollUtil.isEmpty(downloadTasks)) {
            return new StatusDTO();
        }
        DownloadTask downloadTask = downloadTasks.iterator().next();
        DownloadTaskStatusEnum downloadTaskStatusEnum = DownloadTaskStatusEnum.getByCode(downloadTask.getTaskStatus());
        if (Objects.isNull(downloadTaskStatusEnum)) {
            return new StatusDTO();
        }
        return StatusDTO.builder()
                .statusDesc(downloadTaskStatusEnum.getDesc())
                .statusValue(downloadTaskStatusEnum.getCode())
                .build();
    }
}
